﻿using DynamicProxy.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DynamicProxy.AOP
{
    /// <summary>
    /// AOP拦截器
    /// </summary>
    public class AOPInterceptor : IInterceptor
    {
        public object Intercept(Invocation invocation)
        {
            object re = null;
            var attributeList = invocation.DelegateMethod.Method.GetCustomAttributes(true);
            int length = attributeList.Count();

            bool isExecuted = true;
            bool isSucceed = false;

            //前切，若返回false则跳出前切链，跳过执行直接进入后切
            for (int i = 0; i < length; i++)
            {
                AOPBeforeAttribute a = attributeList.ElementAt(i) as AOPBeforeAttribute;
                if (a != null)
                {
                    a = a.Fill(invocation);
                    if (!a.BeforeExecute())
                    {
                        isExecuted = false;
                        break;
                    }
                }
            }
            try
            {
                if (isExecuted)
                {
                    re = invocation.Process();
                    isSucceed = true;
                }
            }
            finally
            {
                //后切，若返回false则跳出后切链（注意，即使被后切的程序报错也执行）
                for (int i = 0; i < length; i++)
                {
                    AOPAfterAttribute a = attributeList.ElementAt(i) as AOPAfterAttribute;
                    if (a != null)
                    {
                        a = a.Fill(invocation);
                        if (!a.AfterExecute(isExecuted, isSucceed))
                        {
                            break;
                        }
                    }
                }
            }
            if (!isExecuted)
            {
                //如果action未执行，给出默认值而非null值
                Type type = invocation.DelegateMethod.Method.ReturnType;
                if (type != typeof(void))
                {
                    re = Activator.CreateInstance(type);
                }
            }
            return re;
        }
    }
}
